package com.eischet.lookup.web;

import org.apache.log4j.Logger;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * This Servlet acts as a front-end to a WebApplication bean, which is configured in the
 * Spring web application context. Requests are routed to that bean.
 */
public class Servlet extends HttpServlet {

    private final Logger logger = Logger.getLogger(getClass());
    private WebApplication application = null;
    private long requestId = 0;

    /**
     * Retrieves the web application from the application context.
     * This method is called by the servlet container automatically when the servlet is loaded.
     * @param config            a J2EE ServletConfig, provided by the servlet container
     * @throws javax.servlet.ServletException generically
     */
    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        if (logger.isInfoEnabled()) {
            logger.info("connecting web application...");
        }
        WebApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(config.getServletContext());
        application = context.getBean("application", WebApplication.class);
        if (logger.isInfoEnabled()) {
            logger.info("connected to: " + application);
        }
    }

    /**
     * processes GET requests
     *
     * @param request           http request
     * @param response          http response
     * @throws javax.servlet.ServletException if all else fails
     * @throws java.io.IOException      if all else fails
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        dispatch(request, response);
    }

    /**
     * processes POST requests
     *
     * @param request           http request
     * @param response          http response
     * @throws javax.servlet.ServletException if all else fails
     * @throws java.io.IOException      if all else fails
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        dispatch(request, response);
    }

    /**
     * dispatches requests to the wrapped application bean
     *
     * @param request           http request
     * @param response          http response
     * @throws javax.servlet.ServletException if all else fails
     * @throws java.io.IOException      if all else fails
     */
    private void dispatch(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // The request ID counter can fail under very high load if the servlet runs multithreaded, but it is not
        // critical and just a debugging aid, so I have decided to ignore that issue for now. SE
        ++requestId;
        long id = requestId;
        //try {
        //    request.setCharacterEncoding("utf-8");
        //} catch (UnsupportedEncodingException e) {
        //    logger.error("failed setting request.characterEncoding='utf-8'", e);
        //}
        dumpRequest(id, request, response);
        try {
            application.dispatch(request, response);
            if (logger.isDebugEnabled()) {
                logger.debug(String.format("[%s] finished processing without error", id));
            }
        } catch (Exception ex) {
            logger.error(ex, ex);
        }
    }

    /**
     * Dumps request data, as a debugging aid.
     * @param id            the request ID
     * @param request       the request wrapper
     * @param response      the response wrapper
     */
    private void dumpRequest(long id, HttpServletRequest request, HttpServletResponse response) {
        if (logger.isDebugEnabled()) {
            logger.debug(String.format("[%s] %s request %s => %s", id, request.getMethod(), request, response));
        }
    }

    /**
     * @return a String representation of this object
     */
    @Override
    public String toString() {
        return String.format("Servlet(requestId=%d)", requestId);
    }
}
